package com.ruoyi.newSystem.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.admin.domain.LlmAppSettings;
import com.ruoyi.admin.service.app.LlmAppSettingsService;
import com.ruoyi.common.core.domain.entity.*;
import com.ruoyi.common.enums.MenuTypeEnum;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.newSystem.bean.output.AuthPermissionInfoRespVO;
import com.ruoyi.newSystem.domain.SystemKnowledgeRegister;
import com.ruoyi.newSystem.mapper.RoleMenuMapper;
import com.ruoyi.newSystem.mapper.UserDeptMapper;
import com.ruoyi.newSystem.mapper.UserRoleMapper;
import com.ruoyi.newSystem.service.MenuService;
import com.ruoyi.newSystem.service.PermissionService;
import com.ruoyi.newSystem.service.RoleService;
import com.ruoyi.newSystem.service.SystemKnowledgeRegisterService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.collection.CollectionUtils.convertSet;
import static com.ruoyi.common.utils.collection.CollectionUtils.filterList;


/**
 * 权限 Service 实现类
 *
 * @author 后台源码
 */
@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {

    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private UserDeptMapper userDeptMapper;

    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;

    @Resource
    private SystemKnowledgeRegisterService systemKnowledgeRegisterServiceImpl;

    @Resource
    private LlmAppSettingsService llmAppSettingsService;


    // ========== 角色-菜单的相关方法  ==========

    @Override
    // allEntries 清空所有缓存，主要一次更新涉及到的 menuIds 较多，反倒批量会更快
    public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
        // 获得角色拥有菜单编号
        Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
        // 计算新增和删除的菜单编号
        if (CollUtil.isNotEmpty(dbMenuIds)) {
            roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, dbMenuIds);
        }
        // 执行新增和删除。对于已经授权的菜单，不用做任何处理
        if (CollUtil.isNotEmpty(menuIds)) {
            roleMenuMapper.insertBatch(CollectionUtils.convertList(menuIds, menuId -> {
                RoleMenuDO entity = new RoleMenuDO();
                entity.setRoleId(roleId);
                entity.setMenuId(menuId);
                entity.setCreateTime(LocalDateTime.now());
                entity.setModifyTime(LocalDateTime.now());
                return entity;
            }));
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processRoleDeleted(Long roleId) {
        // 标记删除 UserRole
        userRoleMapper.deleteListByRoleId(roleId);
        // 标记删除 RoleMenu
        roleMenuMapper.deleteListByRoleId(roleId);
    }

    @Override
    public void processMenuDeleted(Long menuId) {
        roleMenuMapper.deleteListByMenuId(menuId);
    }

    @Override
    public Set<Long> getRoleMenuListByRoleId(Collection<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return Collections.emptySet();
        }

        // 如果是管理员的情况下，获取全部菜单编号
        if (roleService.hasAnySuperAdmin(roleIds)) {
            return convertSet(menuService.getMenuList(), MenuDO::getId);
        }
        // 如果是非管理员的情况下，获得拥有的菜单编号
        return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId);
    }

    @Override
    public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) {
        return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId);
    }

    // ========== 用户-角色的相关方法  ==========

    @Override
    public void assignUserRole(Long userId, Set<Long> roleIds) {
        //删除改用户所有的角色
        userRoleMapper.deleteListByUserId(userId);
        // 将现在的角色全部赋予给用户
        if (!CollectionUtil.isEmpty(roleIds)) {
            userRoleMapper.insertBatch(CollectionUtils.convertList(roleIds, roleId -> {
                UserRoleDO entity = new UserRoleDO();
                entity.setUserId(userId);
                entity.setRoleId(roleId);
                return entity;
            }));
        }
    }

    @Override
    public void assignUserDept(Long userId, Set<Long> deptIds) {
        // 获得角色拥有角色编号
        Set<Long> dbDeptIds = convertSet(userDeptMapper.selectListByUserId(userId),
                UserDeptDO::getDeptId);
        // 计算新增和删除的角色编号
        Collection<Long> createDeptIds = CollUtil.subtract(deptIds, dbDeptIds);
        Collection<Long> deleteMenuIds = CollUtil.subtract(dbDeptIds, deptIds);
        // 执行新增和删除。对于已经授权的角色，不用做任何处理
        if (!CollectionUtil.isEmpty(createDeptIds)) {
            userDeptMapper.insertBatch(CollectionUtils.convertList(createDeptIds, roleId -> {
                UserDeptDO entity = new UserDeptDO();
                entity.setUserId(userId);
                entity.setDeptId(roleId);
                return entity;
            }));
        }
        if (!CollectionUtil.isEmpty(deleteMenuIds)) {
            userDeptMapper.deleteListByUserIdAndDeptIds(userId, deleteMenuIds);
        }
    }

    @Override
    public void processUserDeleted(Long userId) {
        userRoleMapper.deleteListByUserId(userId);
    }

    @Override
    public Set<Long> getUserRoleIdListByUserId(Long userId) {
        return convertSet(userRoleMapper.selectListByUserId(userId), UserRoleDO::getRoleId);
    }

    @Override
    public Set<Long> getUserDeptIdListByUserId(Long userId) {
        return convertSet(userDeptMapper.selectListByUserId(userId), UserDeptDO::getDeptId);
    }

    @Override
    public Set<Long> getUserRoleIdListByUserIdFromCache(Long userId) {
        return getUserRoleIdListByUserId(userId);
    }

    @Override
    public List<RoleDO> getUserRoleByUserId(Long userId) {
        return roleService.getRolesByUserId(userId);
    }

    @Override
    public Set<Long> getUserRoleIdListByRoleId(Collection<Long> roleIds) {
        return convertSet(userRoleMapper.selectListByRoleIds(roleIds), UserRoleDO::getUserId);
    }


    // ========== 用户-部门的相关方法  ==========

    @Override
    public void assignRoleDataScope(Long roleId, Integer dataScope, Set<String> dataScopeAccessIds) {
        roleService.updateRoleDataScope(roleId, dataScope, dataScopeAccessIds);
    }

    @Override
    public void assignRoleDataset(Long roleId, String dataSet) {
        roleService.updateRoleDataSet(roleId, dataSet);
    }


    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private PermissionServiceImpl getSelf() {
        return SpringUtils.getBean(getClass());
    }


    @Override
    public List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList) {
// 移除按钮
        menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType()));
        // 排序，保证菜单的有序性
        menuList.sort(Comparator.comparing(MenuDO::getSort));

        // 构建菜单树
        // 使用 LinkedHashMap 的原因，是为了排序 。实际也可以用 Stream API ，就是太丑了。
        Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
        menuList.forEach(menu -> {
            AuthPermissionInfoRespVO.MenuVO menuVO = new AuthPermissionInfoRespVO.MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            treeNodeMap.put(menu.getId(), menuVO);
        });
        // 处理父子关系
        treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuDO.ID_ROOT)).forEach(childNode -> {
            // 获得父节点
            AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
            if (parentNode == null) {
                LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
                        childNode.getId(), childNode.getParentId());
                return;
            }
            // 将自己添加到父节点中
            if (parentNode.getChildren() == null) {
                parentNode.setChildren(new ArrayList<>());
            }
            parentNode.getChildren().add(childNode);
        });
        // 获得到所有的根节点
        return filterList(treeNodeMap.values(), node -> MenuDO.ID_ROOT.equals(node.getParentId()));
    }

    @Override
    public List<AuthPermissionInfoRespVO.MenuVO> buildMenuTreeSelect() {
        List<MenuDO> menuList = menuService.getMenuList();
        // 排序，保证菜单的有序性
        menuList.sort(Comparator.comparing(MenuDO::getSort));

        List<AuthPermissionInfoRespVO.MenuVO> newMenuList = new ArrayList<>();
        menuList.forEach(menu -> {
            //如果不是智能体就添加到集合中
            if (!MenuTypeEnum.ZHINENG.getType().equals(menu.getType())) {
                AuthPermissionInfoRespVO.MenuVO menuVO = new AuthPermissionInfoRespVO.MenuVO();
                BeanUtils.copyProperties(menu, menuVO);
                menuVO.setTreeKey(menu.getId().toString());
                newMenuList.add(menuVO);
            }

        });
        //已启用的智能应用
        List<LlmAppSettings> appSettingsByEnable = llmAppSettingsService.getAppSettingsByEnable("Y");

        List<AuthPermissionInfoRespVO.MenuVO> menuVOS = new ArrayList<>();

        //将所有已经发布的智能应用加入到树中
        for (LlmAppSettings llmAppSettings : appSettingsByEnable) {
            try {
                //每个智能应用都需要绑定一个实例，这里就是将实例id 取出来
                Long l = Long.valueOf(llmAppSettings.getType());
                MenuDO menu = menuService.getMenu(l);
                AuthPermissionInfoRespVO.MenuVO menuVO = new AuthPermissionInfoRespVO.MenuVO();
                BeanUtils.copyProperties(menu, menuVO);
                menuVO.setChildren(new ArrayList<>());
                menuVO.setName(llmAppSettings.getName());
                //将自己的id 加上 智能体id就得到唯一id
                menuVO.setTreeKey(menu.getId() + ":" + llmAppSettings.getId());
                //将智能体id 加入到数据中
                menuVO.setAppSettingId(llmAppSettings.getId());
                buildTree(menuVO, newMenuList, menu.getId() + "", menuVO.getAppSettingId());
                //将智能体和本体id 存放到一起
                menuVOS.add(menuVO);
            } catch (Exception e) {
                log.error("错误数据:{}", llmAppSettings.getType(), e);

            }

        }
        return menuVOS;
    }


    private void buildTree(AuthPermissionInfoRespVO.MenuVO menus, List<AuthPermissionInfoRespVO.MenuVO> menuVOS, String parentId, Integer appSettingId) {
        // 预过滤符合条件的菜单，避免每次都遍历整个列表
        List<AuthPermissionInfoRespVO.MenuVO> childMenus = menuVOS.stream()
                .filter(menu -> menu.getParentId().equals(Long.valueOf(parentId)))
                .toList();

        for (AuthPermissionInfoRespVO.MenuVO menu : childMenus) {
            AuthPermissionInfoRespVO.MenuVO menuVO = new AuthPermissionInfoRespVO.MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            menuVO.setChildren(new ArrayList<>());
            //当不是智能应用时候将智能体id 往下扩散
            if (!parentId.equals("0")) {
                menuVO.setTreeKey(menu.getId().toString() + ":" + appSettingId);
                menuVO.setAppSettingId(appSettingId);
            }
            //当这个节点是一个知识库时候就需要取查询知识库注册表然后将所有知识库查询出来
            //因为类型为知识库就是最终节点，且所有知识库只有一层所以不需要往下查询
            if (Objects.equals(menu.getType(), MenuTypeEnum.DATASET.getType())) {
                setDataSetToTree(menuVO);
            }
            List<AuthPermissionInfoRespVO.MenuVO> children = menus.getChildren();
            children.add(menuVO);
            buildTree(menuVO, menuVOS, menu.getId() + "", appSettingId);
        }

    }


    public void setDataSetToTree(AuthPermissionInfoRespVO.MenuVO menuVO) {
        //查询注册的知识库
        SystemKnowledgeRegister systemKnowledgeRegister = new SystemKnowledgeRegister();
        systemKnowledgeRegister.setMenuId(menuVO.getParentId());
        SystemKnowledgeRegister systemKnowledgeRegisterByMenuId = systemKnowledgeRegisterServiceImpl.getSystemKnowledgeRegisterByMenuId(systemKnowledgeRegister);
        if (systemKnowledgeRegisterByMenuId != null) {
            //将注册的知识库所有记录查询出来
            List<Map<String, Object>> dataSet = systemKnowledgeRegisterServiceImpl.getDataSet(systemKnowledgeRegisterByMenuId.getKnowledgeTable());
            //迭代所有记录筛入到树中
            for (Map<String, Object> stringObjectMap : dataSet) {
                AuthPermissionInfoRespVO.MenuVO datasetVo = new AuthPermissionInfoRespVO.MenuVO();
                datasetVo.setName(stringObjectMap.get("name").toString());
                datasetVo.setCategoryId(menuVO.getCategoryId());
                datasetVo.setParentId(menuVO.getId());
                datasetVo.setId(-1L);
                datasetVo.setType(5);
                datasetVo.setDataSetId(stringObjectMap.get("dataset_code").toString());
                datasetVo.setAlwaysShow(true);
                datasetVo.setTreeKey(stringObjectMap.get("id").toString());
                List<AuthPermissionInfoRespVO.MenuVO> children1 = menuVO.getChildren();
                children1.add(datasetVo);
                menuVO.setChildren(children1);
            }
        }
    }

    //系统管理
    @Override
    public List<AuthPermissionInfoRespVO.MenuVO> buildMenuTreeSystem() {

        List<MenuDO> menuList = menuService.getMenuList();
        // 排序，保证菜单的有序性
        menuList.sort(Comparator.comparing(MenuDO::getSort));
        // 使用 LinkedHashMap 的原因，是为了排序 。实际也可以用 Stream API ，就是太丑了。
        Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
        menuList.forEach(menu -> {
            AuthPermissionInfoRespVO.MenuVO menuVO = new AuthPermissionInfoRespVO.MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            menuVO.setTreeKey(menu.getId().toString());
            treeNodeMap.put(menu.getId(), menuVO);
        });

        // 处理父子关系
        treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuDO.ID_ROOT)).forEach(childNode -> {
            // 获得父节点
            AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
            if (parentNode == null) {
                LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
                        childNode.getId(), childNode.getParentId());
                return;
            }
            // 将自己添加到父节点中
            if (parentNode.getChildren() == null) {
                parentNode.setChildren(new ArrayList<>());
            }
            parentNode.getChildren().add(childNode);
        });
        //提取智能应用为跟节点
        treeNodeMap.values().stream().filter(node -> node.getParentId().equals(MenuDO.ID_ROOT) && !Objects.equals(node.getType(), MenuTypeEnum.ZHINENG.getType())).forEach(childNode -> {

            // 获得父节点
            AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getCategoryId());
            if (parentNode == null) {
                LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
                        childNode.getId(), childNode.getParentId());
                return;
            }
            // 将自己添加到父节点中
            if (parentNode.getChildren() == null) {
                parentNode.setChildren(new ArrayList<>());
            }
            parentNode.getChildren().add(childNode);
        });
        // 获得到所有的根节点
        List<AuthPermissionInfoRespVO.MenuVO> menuVOS = filterList(treeNodeMap.values(), node -> MenuDO.ID_ROOT.equals(node.getParentId()) && MenuTypeEnum.ZHINENG.getType().equals(node.getType()) && node.getCategoryId() != null && node.getCategoryId() == -1);
        List<AuthPermissionInfoRespVO.MenuVO> list = menuVOS.stream().filter(item -> item.getId() == 1).collect(Collectors.toList());
        return list;
    }

    @Override
    public List<MenuDO> getMenuByUserIds(Long userId) {
        return menuService.getMenusByUserId(userId);
    }

    @Override
    public List<AuthPermissionInfoRespVO.MenuVO> buildTreeKnowledge() {
        List<AuthPermissionInfoRespVO.MenuVO> menuVO = new ArrayList<>();
        List<SystemKnowledgeRegister> systemKnowledgeRegister = systemKnowledgeRegisterServiceImpl.getSystemKnowledgeRegister();
        Long i = 1L;
        for (SystemKnowledgeRegister s1 : systemKnowledgeRegister) {
            AuthPermissionInfoRespVO.MenuVO menuVO1 = new AuthPermissionInfoRespVO.MenuVO();
            menuVO1.setId(i);
            menuVO1.setName(s1.getName());
            menuVO1.setParentId(0L);
            menuVO1.setChildren(new ArrayList<>());
            List<Map<String, Object>> dataSet = systemKnowledgeRegisterServiceImpl.getDataSet(s1.getKnowledgeTable());
            for (Map<String, Object> stringObjectMap : dataSet) {
                stringObjectMap.get("id");
                AuthPermissionInfoRespVO.MenuVO children = new AuthPermissionInfoRespVO.MenuVO();
                children.setId(i);
                children.setName(stringObjectMap.get("name").toString());
                children.setParentId(0L);
                List<AuthPermissionInfoRespVO.MenuVO> children1 = menuVO1.getChildren();
                children1.add(children);
                menuVO1.setChildren(children1);
            }
            menuVO.add(menuVO1);
            i++;
        }
        return menuVO;
    }


}
